#pragma once
#include <Image/Image.hpp>
#include <Math/Math.hpp>
#include <3rdParty/boostsignal2.hpp>
#include <Utility/Log.hpp>
namespace zzz{
class SIFT {
public:
  SIFT(){}
  ~SIFT() {
    ClearOctave(gauss_);
    ClearOctave(dog_);
  }

  void FindKeypoint(Image<float> *img) {
    ori_=img;
    ncol_=img->Cols();
    nrow_=img->Rows();
    NSCALE=3;
    OMIN=0;
    NOCTAVE=(int)floor(log(double(Min(ncol_,nrow_)))/log(2.0))-OMIN-3;
    SIGMA = (float)1.6*Pow(2,1/NSCALE);
    INITSIGMA = 0.5f ;
    THRESH = 0; //0.04f / NSCALE / 2 ;
    EDGETHRESH = 10.0;
    IMAGEEDGEDIST = 10;
    zout<<"BuildGaussianOctaves\n";
    BuildGaussianOctaves();
    zout<<"BuildDoGOctaves\n";
    BuildDoGOctaves();
    zout<<"FindLocalMaxima\n";
    FindLocalMaxima();
    zout<<"RefineKeypoint\n";
    RefineKeypoint();
//     int nkey=0;
//     for (size_t i=0; i<keypoint_.size(); i++)
//       nkey+=keypoint_[i].size();
//     zout<<"found:"<<nkey<<endl;
  }

public:
#ifdef ZZZ_LIB_BOOST
  boost::signals2::signal<void(Image<float>*)> ReportBuildGaussian;
  boost::signals2::signal<void(Image<float>*)> ReportBuildOctave;
  boost::signals2::signal<void(Image<float>*,int,int)> ReportMaxima;
#endif

//private:
  typedef vector<vector<Image<float>*> > Octave;
  Image<float> *ori_;
  int ncol_,nrow_; //size
  Octave gauss_,dog_;
  vector<vector<Vector3f> > keypoint_;
  //parameters
  float INITSIGMA, SIGMA, THRESH, EDGETHRESH,IMAGEEDGEDIST;
  int NSCALE, OMIN, NOCTAVE;
  //clear
  void ClearOctave(Octave &octave);

  //refine key point, eliminate low value and edge response
  void RefineKeypoint();
  //find local maxima/minima(init keypoint) 
  void FindLocalMaxima();
  //build dog 
  void BuildDoGOctaves(Image<float> * image);
  void BuildDoGOctaves();
  //build gaussian
  void BuildGaussianOctaves();
  //init the original image, scale and blur
  Image<float> * ScaleInitImage();
  //helper for gaussian, blur
  vector<Image<float> *> BuildGaussianScales(Image<float> * image);
};
}  // namespace zzz
